package org.duomn.ichat.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.Socket;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

import org.duomn.ichat.dao.IUserDao;
import org.duomn.ichat.dao.UserDaoForTest;
import org.duomn.ichat.entity.Message;
import org.duomn.ichat.entity.MsgCatalog;
import org.duomn.ichat.entity.MsgType;
import org.duomn.ichat.entity.User;
import org.duomn.ichat.exception.MsgLoseException;
import org.duomn.ichat.gui.custom.RoundBorder;
import org.duomn.ichat.thread.TCPReceiverThread;
import org.duomn.ichat.thread.TCPThreadAbstract;
import org.duomn.ichat.thread.TCPThreadFactory;
import org.duomn.ichat.thread.TCPThreadPORT;
import org.duomn.ichat.util.Const;
import org.duomn.ichat.util.GBC;
import org.duomn.ichat.util.IconUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 显示好友列表的界面，软件进入的主页面
 * @author duomn
 *
 */
public class MainFrame extends JFrame {
	
	private static final long serialVersionUID = -1257872949092665124L;
	
	private static final Logger logger = LoggerFactory.getLogger(MainFrame.class);
	
	private static final int USER_ITEM_HEIGHT = 50;
	
	Font usual = new Font("宋体", Font.PLAIN, 12);
	RoundBorder roundBorder = new RoundBorder();
	private Color selectedColor = new Color(252, 235, 171);
	private Color passColor = new Color(255, 248, 211);
	
	private JList list;
	private TCPReceiverThread receiver;
	JLabel icoLbl; // 头像的Lbl
	
	private int passIndex = -1;
	
	// TODO 需要使用正确的列表
	IUserDao dao = new UserDaoForTest(); 
	
	private MainFrame() {
		setTitle("iChat1.0");
		setSize(270, 540);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		initData(); // 初始化数据
		getContentPane().add(initTopPane(), BorderLayout.NORTH);
		getContentPane().add(initCenterPane(), BorderLayout.CENTER);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				logger.info("关闭了");
//				new SwingWorker<Void, Void>() {
//					@Override
//					protected Void doInBackground() throws Exception {
//						Map<Integer, User> userMap = Const.get(Const.USER_MAP);
//						for (User user : userMap.values()) {
//							if (user.getId() == Const.<Integer>get(Const.USER_SELF_ID)) continue;
//							MsgSender send = new ChatThreadPORT(user.getHost(), user.getPort()); 
//							if (send.open()) {
//								logger.debug("用户[" + user.getName() + "]在线" );
//								try {
//									send.send(Message.CreateLog().setData(Const.<User>get(Const.USER_SELF)));
//								} catch (MsgLoseException e) {
//									logger.error("发送登陆状态失败", e);
//								}
//								send.close();
//							} else {
//								logger.debug("用户[" + user.getName() + "]不在线");
//								user.setPort(0);
//							}
//						}
//						return null;
//					}
//
//					@Override
//					protected void done() {
//						MainFrame.getInstance().updateData();
//					}
//				}.execute();
				
				Map<Integer, User> userMap = Const.get(Const.USER_MAP);
				for (User user : userMap.values()) {
					if (user.getId() == Const.<Integer>get(Const.USER_SELF_ID)) continue;
					TCPThreadAbstract chatThread = new TCPThreadPORT(user.getHost(), user.getPort()); 
					if (chatThread.openSession()) {
						logger.debug("向用户[" + user.getName() + "]发送离线信号" );
						try {
							Message message = new Message();
							message.src = Const.get(Const.USER_SELF_ID);
							message.msgCatalog = MsgCatalog.CHAT_MSG;
							message.msgType = MsgType.LOGIN_OUT;
							chatThread.send(message);
						} catch (MsgLoseException err) {
							logger.error("发送退出信号失败", err);
						}
						chatThread.closeSession();
					} else {
						logger.debug("用户[" + user.getName() + "]不在线");
						user.setPort(0);
					}
				}
//				MsgSender send = new ChatThreadPORT(, port);
				receiver.close();
			}
		});
		updateData(); // 显示List中的数据
		setVisible(true);
		// 启动监听线程
		receiver = new TCPReceiverThread(Const.<Integer>get(Const.USER_SELF_PORT));
		receiver.start();
	}
	
	/** 初始化数据 */
	private void initData() {
		Map<Integer, User> userMap = dao.listFriends(); 
		for (Entry<Integer, User> item : userMap.entrySet()) {
			if (Const.<Integer>get(Const.USER_SELF_ID) == item.getKey()) {
				item.getValue().setPort(Const.<Integer>get(Const.USER_SELF_PORT));
				Const.put(Const.USER_SELF, item.getValue());
			}
		}
		Const.put(Const.USER_MAP, userMap);
	}
	
	public synchronized void updateData() {
		Map<Integer, User> userMap = Const.get(Const.USER_MAP);
		DefaultListModel model = (DefaultListModel) list.getModel();
		int size = model.getSize();
		if (size == 0) { // 第一次初始化列表
			model.addElement(Const.<User>get(Const.USER_SELF)); // 把自己放在第一个
			for (User item : userMap.values()) {
				if (item.getId() == Const.<Integer>get(Const.USER_SELF_ID)) continue; 
				model.addElement(item);
			}
		} else { // 更新数据后，更新列表
			Set<Integer> already = new HashSet<Integer>();
			for (int i = 0; i < size; i++) {
				int userId = ((User) model.get(i)).getId();
				already.add(userId);
				model.set(i, userMap.get(userId));
			} 
			for (User item : userMap.values()) {
				if (!already.contains(item.getId())) {
					model.addElement(item);
				}
			}
		}
		list.repaint();
	}
	
	private JPanel initTopPane() {
		JPanel topPane = new JPanel(new GridBagLayout());
		topPane.setPreferredSize(new Dimension(200, 70));
		icoLbl = new JLabel();
		icoLbl.setIcon(IconUtil.getIcon("img/online.png", 60, 60));
		icoLbl.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				JOptionPane.showMessageDialog(MainFrame.this, "设置信息");
			}

			public void mouseEntered(MouseEvent e) {
				icoLbl.setBorder(roundBorder);
			}

			public void mouseExited(MouseEvent e) {
				icoLbl.setBorder(null);
			}
			
		});
		topPane.add(icoLbl, new GBC(0, 0, 1, 1).setMargin(6));
		JPanel selfInfo = new JPanel();
		BoxLayout boxLay = new BoxLayout(selfInfo, BoxLayout.Y_AXIS);
		selfInfo.setLayout(boxLay);
		JLabel nameLabel = new JLabel(Const.<User>get(Const.USER_SELF).getName());
		selfInfo.add(nameLabel);
		JLabel statusLbl = new JLabel(Const.<User>get(Const.USER_SELF).getStatus());
		statusLbl.setFont(usual);
		selfInfo.add(statusLbl);
		topPane.add(selfInfo, new GBC(1, 0, 1, 1).setMargin(6).setFill(GBC.HORIZONTAL).setWeight(1, 0));
		return topPane;
	}
	
	// 初始化好友列表
	private JScrollPane initCenterPane() {
		list = new JList(new DefaultListModel());
		list.setBackground(Color.WHITE);
		final JScrollPane scrollPane = new JScrollPane(list, 
				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		list.addMouseListener(new MouseAdapter() {
			
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					User user = (User) list.getSelectedValue();
					ChatFrame.getInstance(user);
				}
			}

			public void mouseEntered(MouseEvent e) {
				int index = list.locationToIndex(e.getPoint());
				if (index != -1) {
					passIndex = index;
					scrollPane.repaint();
				}
			}

			public void mouseExited(MouseEvent e) {
				passIndex = -1;
				scrollPane.repaint();
			}
		});
		
		list.addMouseMotionListener(new MouseMotionAdapter() {
			public void mouseMoved(MouseEvent e) {
				int index = list.locationToIndex(e.getPoint());
				if (index == passIndex) return;
				passIndex = index;
				scrollPane.repaint();
			}
		});
			
		list.setCellRenderer(new FriendListRenderer());
		return scrollPane;
	}
	
	private class FriendListRenderer extends JPanel implements ListCellRenderer {
		private static final long serialVersionUID = -7896767373559848336L;

		private JLabel iconLbl;
		private JLabel nameLbl;
 		private JLabel statusLbl;
 		
		public FriendListRenderer() {
			setLayout(new GridBagLayout());
			iconLbl = new JLabel(IconUtil.getIcon("img/offline.png", 40, 40));
			add(iconLbl, new GBC(0, 0, 1, 1).setAnchor(GBC.WEST).setWeight(0.f, 0.f).setMargin(4, 4));
			setPreferredSize(new Dimension(200, USER_ITEM_HEIGHT));
			JPanel pane = new JPanel();
			pane.setOpaque(false);
			BoxLayout boxLay = new BoxLayout(pane, BoxLayout.Y_AXIS);
			pane.setLayout(boxLay);
			nameLbl = new JLabel();
			nameLbl.setFont(usual);
			pane.add(nameLbl);
			statusLbl = new JLabel();
			statusLbl.setFont(usual);
			pane.add(statusLbl);
			add(pane, new GBC(1, 0, 1, 1).setFill(GBC.HORIZONTAL).setWeight(1.f, 0.f).setMargin(4, 10, 4, 0).setPadding(4, 4));
		}
		
		@Override
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			User user = (User) value;
			if (isSelected) {
				setOpaque(true);
				setBackground(selectedColor);
				iconLbl.setBorder(roundBorder);
			} else {
				if (passIndex == index) {
					setOpaque(true);
					setBackground(passColor);
				} else {
					setOpaque(false);
				}
				iconLbl.setBorder(null);
			}
			
			if (user.getPort() == 0) { // 未登录
				iconLbl.setIcon(IconUtil.getIcon("img/offline.png", 40, 40));
			} else { // 登录
				iconLbl.setIcon(IconUtil.getIcon("img/online.png", 40, 40));
			}
			
			nameLbl.setText(user.getName());
			statusLbl.setText(user.getStatus());
			return this;
		}

	}
	
	public static boolean isPortUsing(String host, int port) {  
		try {
	        Socket s = new Socket(host, port);  
	        s.close();  
	        return true;
		} catch (IOException e) {
			return false;
		}
    }  

	public void checkUserStatue() {
		// TODO  检查好友的状态，每隔5分钟，由库中默认获取一次好友状态
		// 1.所有的好友列表中默认是不在线的.
		// 2.登录后主动修改自己的在线状态.
		// 3.通知其他好友自己的在线状态
		new SwingWorker<Void, Void>() {
			@Override
			protected Void doInBackground() throws Exception {
				try {
					Map<Integer, User> userMap = Const.get(Const.USER_MAP);
					for (User user : userMap.values()) {
						if (user.getId() == Const.<Integer>get(Const.USER_SELF_ID)) continue;
						// UIHandler使用空实现
						TCPThreadAbstract chatThread = 
								TCPThreadFactory.createChatMsgPortThread(user.getHost(), user.getPort());
						if (chatThread.openSession()) {
							logger.debug("用户[" + user.getName() + "]在线" );
							try {
								Message message = new Message();
								message.src = Const.get(Const.USER_SELF_ID);
								message.data = Const.get(Const.USER_SELF);
								message.msgCatalog = MsgCatalog.CHAT_MSG;
								message.msgType = MsgType.LOGIN_IN;
								chatThread.send(message);
							} catch (MsgLoseException e) {
								logger.error("发送登陆状态失败", e);
							}
							chatThread.closeSession();
						} else {
							logger.debug("用户[" + user.getName() + "]不在线");
							user.setPort(0);
						}
					}
				} catch (Exception e) {
					logger.error("检查好友在线状态异常", e);
					throw e;
				}
				return null;
			}

			@Override
			protected void done() {
				MainFrame.getInstance().updateData();
			}
		}.execute();;
		
	}
	
	// 提供单例获取的接口
	public static MainFrame getInstance() {
		return SingleHandler.instance;
	}
	
	private static class SingleHandler {
		private static final MainFrame instance = new MainFrame();
	}
	
	public static void main(String[] args) {
		System.setProperty("java.awt.im.style","on-the-spot"); // 去掉输入法的窗口
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				// 计算当前的启动的端口
				String host = "127.0.0.1";
				for (int i = 0; i < 10; i++) {
					if (isPortUsing(host, i + 8090)) continue;
					Const.put(Const.USER_SELF_PORT, i + 8090);
					Const.put(Const.USER_SELF_ID, i);
					break;
				}
				
				MainFrame mf = MainFrame.getInstance();
				mf.checkUserStatue(); // 检查用户的状态，并赋值
			}
		});
	}
	
}
